package cn.iocoder.yudao.module.lowcode.controller.admin.generic;

import cn.hutool.core.util.StrUtil;
import cn.idev.excel.EasyExcel;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import cn.iocoder.yudao.framework.excel.core.handler.ColumnWidthMatchStyleStrategy;
import cn.iocoder.yudao.module.lowcode.controller.admin.generic.vo.*;
import cn.iocoder.yudao.module.lowcode.service.generic.GenericTableService;
import cn.iocoder.yudao.module.lowcode.service.generic.GenericTableServiceEnhancer;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

@Tag(name = "低代码 - 通用表格管理")
@RestController
@RequestMapping("/lowcode/generic/{tableName}")
@Validated
@Slf4j
public class GenericTableController {

    @Resource
    private GenericTableService genericTableService;

    @Resource
    private GenericTableServiceEnhancer tableServiceEnhancer;

    @GetMapping("/page")
    @Operation(summary = "获得通用表格分页")
    @PreAuthorize("@ss.hasPermission('lowcode:generic:' + #tableName + ':query')")
    public CommonResult<PageResult<GenericTableRespVO>> getGenericTablePage(
            @PathVariable("tableName") String tableName,
            @RequestParam(value = "dataSourceId", defaultValue = "0") Long dataSourceId,
            @RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
            @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
        
        log.info("[getGenericTablePage] 查询通用表格分页: tableName={}, dataSourceId={}, pageNo={}, pageSize={}", 
                tableName, dataSourceId, pageNo, pageSize);
        
        // 构造请求对象
        GenericTablePageReqVO pageReqVO = new GenericTablePageReqVO();
        pageReqVO.setDataSourceId(dataSourceId);
        pageReqVO.setPageNo(pageNo);
        pageReqVO.setPageSize(pageSize);
        
        PageResult<GenericTableRespVO> pageResult = genericTableService.getGenericTablePage(tableName, pageReqVO);
        return success(pageResult);
    }

    @PostMapping("/create")
    @Operation(summary = "创建通用表格记录")
    @Parameter(name = "tableName", description = "表名", required = true, example = "sys_user")
    @PreAuthorize("@ss.hasPermission('lowcode:generic:' + #tableName + ':create')")
    public CommonResult<Long> createGenericTable(@PathVariable("tableName") String tableName,
                                                  @RequestBody Map<String, Object> requestData) {
        
        log.info("[createGenericTable] 创建通用表格记录: tableName={}, requestData={}", tableName, requestData);
        
        // 支持两种请求格式：
        // 1. 标准格式：{"dataSourceId": 0, "data": {"field1": "value1", "field2": "value2"}}
        // 2. 扁平格式：{"field1": "value1", "field2": "value2"} （默认使用dataSourceId=0）
        
        GenericTableSaveReqVO createReqVO = new GenericTableSaveReqVO();
        
        if (requestData.containsKey("dataSourceId") && requestData.containsKey("data")) {
            // 标准格式
            createReqVO.setDataSourceId(Long.valueOf(requestData.get("dataSourceId").toString()));
            createReqVO.setData((Map<String, Object>) requestData.get("data"));
        } else {
            // 扁平格式，默认使用主数据源
            createReqVO.setDataSourceId(0L);
            createReqVO.setData(requestData);
        }
        
        log.info("[createGenericTable] 转换后的请求: tableName={}, dataSourceId={}", 
                tableName, createReqVO.getDataSourceId());
        
        Long id = genericTableService.createGenericTable(tableName, createReqVO);
        return success(id);
    }

    @PutMapping("/update")
    @Operation(summary = "更新通用表格记录")
    @Parameter(name = "tableName", description = "表名", required = true, example = "sys_user")
    @PreAuthorize("@ss.hasPermission('lowcode:generic:' + #tableName + ':update')")
    public CommonResult<Boolean> updateGenericTable(@PathVariable("tableName") String tableName,
                                                     @RequestBody Map<String, Object> requestData) {
        
        log.info("[updateGenericTable] 更新通用表格记录: tableName={}, requestData={}", tableName, requestData);
        
        // 支持两种请求格式：
        // 1. 标准格式：{"id": 1, "dataSourceId": 0, "data": {"field1": "value1", "field2": "value2"}}
        // 2. 扁平格式：{"id": 1, "field1": "value1", "field2": "value2"} （默认使用dataSourceId=0）
        
        GenericTableSaveReqVO updateReqVO = new GenericTableSaveReqVO();
        
        if (requestData.containsKey("dataSourceId") && requestData.containsKey("data")) {
            // 标准格式
            updateReqVO.setId(Long.valueOf(requestData.get("id").toString()));
            updateReqVO.setDataSourceId(Long.valueOf(requestData.get("dataSourceId").toString()));
            updateReqVO.setData((Map<String, Object>) requestData.get("data"));
        } else {
            // 扁平格式，默认使用主数据源
            updateReqVO.setDataSourceId(0L);
            
            // 提取 id 字段
            if (requestData.containsKey("id")) {
                updateReqVO.setId(Long.valueOf(requestData.get("id").toString()));
                // 创建数据副本，移除 id 字段
                Map<String, Object> data = new HashMap<>(requestData);
                data.remove("id");
                updateReqVO.setData(data);
            } else {
                updateReqVO.setData(requestData);
            }
        }
        
        log.info("[updateGenericTable] 转换后的请求: tableName={}, id={}, dataSourceId={}", 
                tableName, updateReqVO.getId(), updateReqVO.getDataSourceId());
        
        genericTableService.updateGenericTable(tableName, updateReqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除通用表格记录")
    @Parameters({
        @Parameter(name = "tableName", description = "表名", required = true, example = "sys_user"),
        @Parameter(name = "id", description = "编号", required = true, example = "1024"),
        @Parameter(name = "dataSourceId", description = "数据源ID", required = true, example = "0")
    })
    @PreAuthorize("@ss.hasPermission('lowcode:generic:' + #tableName + ':delete')")
    public CommonResult<Boolean> deleteGenericTable(@PathVariable("tableName") String tableName,
                                                     @RequestParam("id") Long id,
                                                     @RequestParam("dataSourceId") Long dataSourceId) {
        
        log.info("[deleteGenericTable] 删除通用表格记录: tableName={}, id={}, dataSourceId={}", 
                tableName, id, dataSourceId);
        
        genericTableService.deleteGenericTable(tableName, id, dataSourceId);
        return success(true);
    }

    @DeleteMapping("/batch-delete")
    @Operation(summary = "批量删除通用表格记录")
    @Parameters({
        @Parameter(name = "tableName", description = "表名", required = true, example = "sys_user"),
        @Parameter(name = "ids", description = "编号列表", required = true, example = "1,2,3"),
        @Parameter(name = "dataSourceId", description = "数据源ID", required = true, example = "0")
    })
    @PreAuthorize("@ss.hasPermission('lowcode:generic:' + #tableName + ':delete')")
    public CommonResult<Boolean> batchDeleteGenericTable(@PathVariable("tableName") String tableName,
                                                          @RequestParam("ids") String ids,
                                                          @RequestParam("dataSourceId") Long dataSourceId) {
        
        log.info("[batchDeleteGenericTable] 批量删除通用表格记录: tableName={}, ids={}, dataSourceId={}", 
                tableName, ids, dataSourceId);
        
        // 解析ID列表
        List<Long> idList = parseIds(ids);
        if (idList.isEmpty()) {
            return success(true);
        }
        
        genericTableService.batchDeleteGenericTable(tableName, idList, dataSourceId);
        return success(true);
    }

    @GetMapping("/export")
    @Operation(summary = "导出通用表格")
    @Parameter(name = "tableName", description = "表名", required = true, example = "sys_user")
    @PreAuthorize("@ss.hasPermission('lowcode:generic:' + #tableName + ':export')")
    public void exportGenericTable(@PathVariable("tableName") String tableName,
                                   @RequestParam(value = "dataSourceId", defaultValue = "0") Long dataSourceId,
                                   @RequestParam Map<String, Object> allParams,
                                   HttpServletResponse response) throws IOException {
        
        log.info("[exportGenericTable] 导出通用表格: tableName={}, dataSourceId={}", tableName, dataSourceId);
        
        // 构建导出请求VO，支持扁平化参数
        GenericTableExportReqVO exportReqVO = new GenericTableExportReqVO();
        exportReqVO.setDataSourceId(dataSourceId);
        
        // 从所有参数中提取搜索参数（排除系统参数）
        Map<String, Object> searchParams = new HashMap<>();
        for (Map.Entry<String, Object> entry : allParams.entrySet()) {
            String key = entry.getKey();
            // 排除系统参数
            if (!"dataSourceId".equals(key) && !"sortField".equals(key) && !"sortOrder".equals(key)) {
                searchParams.put(key, entry.getValue());
            }
        }
        
        if (!searchParams.isEmpty()) {
            exportReqVO.setSearchParams(searchParams);
        }
        
        // 设置排序参数
        if (allParams.containsKey("sortField")) {
            exportReqVO.setSortField(allParams.get("sortField").toString());
        }
        if (allParams.containsKey("sortOrder")) {
            exportReqVO.setSortOrder(allParams.get("sortOrder").toString());
        }
        
        List<GenericTableRespVO> list = genericTableService.getGenericTableList(tableName, exportReqVO);
        
        // 写入Excel导出的逻辑
        writeExcelData(response, tableName + ".xls", "数据", list);
    }
    
    /**
     * 写入动态数据到Excel
     */
    private void writeExcelData(HttpServletResponse response, String filename, String sheetName, 
                                List<GenericTableRespVO> data) throws IOException {
        // 如果没有数据，创建空文件
        if (data == null || data.isEmpty()) {
            response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename));
            response.setContentType("application/vnd.ms-excel;charset=UTF-8");
            response.getOutputStream().write(new byte[0]);
            return;
        }
        
        // 获取所有字段名（从第一行数据中获取）
        Map<String, Object> firstRow = data.get(0);
        List<String> headers = new ArrayList<>(firstRow.keySet());
        
        // 使用 EasyExcel 直接写入
        try {
            EasyExcel.write(response.getOutputStream())
                    .autoCloseStream(false) // 不要自动关闭，交给 Servlet 自己处理
                    .registerWriteHandler(new ColumnWidthMatchStyleStrategy()) // 基于 column 长度，自动适配
                    .head(createDynamicHead(headers))
                    .sheet(sheetName)
                    .doWrite(convertToRowData(data, headers));
            
            // 设置响应头
            response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename));
            response.setContentType("application/vnd.ms-excel;charset=UTF-8");
            
        } catch (Exception e) {
            log.error("[writeExcelData] Excel导出失败", e);
            throw new IOException("Excel导出失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 创建动态表头
     */
    private List<List<String>> createDynamicHead(List<String> headers) {
        List<List<String>> head = new ArrayList<>();
        for (String header : headers) {
            List<String> headColumn = new ArrayList<>();
            headColumn.add(header);
            head.add(headColumn);
        }
        return head;
    }
    
    /**
     * 转换数据为行数据
     */
    private List<List<Object>> convertToRowData(List<GenericTableRespVO> data, List<String> headers) {
        List<List<Object>> rowData = new ArrayList<>();
        for (GenericTableRespVO row : data) {
            List<Object> rowValues = new ArrayList<>();
            for (String header : headers) {
                Object value = row.get(header);
                rowValues.add(value != null ? value.toString() : "");
            }
            rowData.add(rowValues);
        }
        return rowData;
    }

    @GetMapping("/config")
    @Operation(summary = "获取表配置信息")
    @Parameter(name = "tableName", description = "表名", required = true, example = "sys_user")
    @PreAuthorize("@ss.hasPermission('lowcode:generic:' + #tableName + ':query')")
    public CommonResult<GenericTableConfigRespVO> getTableConfig(@PathVariable("tableName") String tableName,
                                                                  @RequestParam(value = "dataSourceId", defaultValue = "0") Long dataSourceId) {
        
        log.info("[getTableConfig] 获取表配置信息: tableName={}, dataSourceId={}", tableName, dataSourceId);
        
        GenericTableConfigRespVO config = genericTableService.getTableConfig(tableName, dataSourceId);
        return success(config);
    }

    @PostMapping("/init-magic-api")
    @Operation(summary = "为表初始化 Magic API 接口")
    @Parameter(name = "tableName", description = "表名", required = true, example = "sys_user")
    @PreAuthorize("@ss.hasPermission('lowcode:generic:' + #tableName + ':query')")
    public CommonResult<Boolean> initMagicApiForTable(@PathVariable("tableName") String tableName,
                                                       @RequestParam(value = "dataSourceId", defaultValue = "0") Long dataSourceId,
                                                       @RequestParam(value = "tableComment", required = false) String tableComment) {
        
        log.info("[initMagicApiForTable] 为表初始化 Magic API 接口: tableName={}, dataSourceId={}", tableName, dataSourceId);
        
        try {
            // 如果没有提供表注释，获取表配置中的注释
            if (StrUtil.isEmpty(tableComment)) {
                GenericTableConfigRespVO config = genericTableService.getTableConfig(tableName, dataSourceId);
                tableComment = config.getTableComment();
            }
            
            // 触发 Magic API 接口生成
            tableServiceEnhancer.notifyTableCreated(tableName, dataSourceId, tableComment);
            
            return success(true);
            
        } catch (Exception e) {
            log.error("[initMagicApiForTable] 为表 {} 初始化 Magic API 接口失败", tableName, e);
            return CommonResult.error(500, "初始化 Magic API 接口失败: " + e.getMessage());
        }
    }

    /**
     * 解析ID字符串为ID列表
     *
     * @param ids ID字符串，格式：1,2,3
     * @return ID列表
     */
    private List<Long> parseIds(String ids) {
        List<Long> idList = new ArrayList<>();
        if (StrUtil.isEmpty(ids)) {
            return idList;
        }
        
        String[] idArray = ids.split(",");
        for (String idStr : idArray) {
            if (StrUtil.isNotEmpty(idStr.trim())) {
                try {
                    idList.add(Long.valueOf(idStr.trim()));
                } catch (NumberFormatException e) {
                    log.warn("[parseIds] ID格式错误: {}", idStr, e);
                    // 跳过格式错误的ID
                }
            }
        }
        return idList;
    }

}